package org.xcorpio.java8.chapter11;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.stream.Collectors;

public class MakingCodeNonBlocking {

    public static void main(String[] args) {
        List<SleepTask> tasks = Arrays.asList(new SleepTask("Tom"), new SleepTask("Jack"), new SleepTask("Thor"),
                new SleepTask("Y"), new SleepTask("Z"));

        long start = System.currentTimeMillis();
        System.out.println("sequential start...");
        List<String> collect = tasks.stream()
                .map(task -> String.format("%s", task.sleepTwoSeconds()))
                .collect(Collectors.toList());
        System.out.println(collect);
        System.out.println("takes: " + (System.currentTimeMillis() - start) + "ms");

        start = System.currentTimeMillis();
        System.out.println("parallelizing...");
        collect = tasks.parallelStream()
                .map(task -> String.format("%s", task.sleepTwoSeconds()))
                .collect(Collectors.toList());
        System.out.println(collect);
        System.out.println("takes: " + (System.currentTimeMillis() - start) + "ms");

        start = System.currentTimeMillis();
        System.out.println("asynchronous...");
        List<CompletableFuture<String>> collect2 = tasks.stream()
                .map(task -> CompletableFuture.supplyAsync(() -> task.sleepTwoSeconds()))
                .collect(Collectors.toList());
        List<String> collect3 = collect2.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
        System.out.println(collect3);
        System.out.println("takes: " + (System.currentTimeMillis() - start) + "ms");

        // NThreads = NCPU * UCPU * (1 + W/C)
        // Custom Executor
        ExecutorService executor = Executors.newFixedThreadPool(Math.min(tasks.size(), 100), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setDaemon(true);
                return t;
            }
        });
        start = System.currentTimeMillis();
        System.out.println(executor + " custom executor...");
        List<CompletableFuture<String>> collect4 = tasks.stream()
                .map(task -> CompletableFuture.supplyAsync(() -> task.sleepTwoSeconds(), executor))
                .collect(Collectors.toList());
        List<String> collect5 = collect4.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
        System.out.println(collect5);
        System.out.println("takes: " + (System.currentTimeMillis() - start) + "ms");
        // executor.shutdown();
    }
}

class SleepTask {

    public String name;

    public SleepTask(String name) {
        this.name = name;
    }

    public String sleepTwoSeconds() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return this.name;
    }

    public void sleepRun() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}